vulkan: implement subpixel positioning
authorMatthias Clasen <mclasen@redhat.com>
Thu, 25 Jul 2019 21:50:31 +0000 (17:50 -0400)
committerMatthias Clasen <mclasen@redhat.com>
Sun, 28 Jul 2019 20:42:52 +0000 (16:42 -0400)
Pass the glyph position into the glyph caching functions,
not just the glyph index. This allows us to cache different
images for different subpixel positions.

gsk/vulkan/gskvulkancolortextpipeline.c
gsk/vulkan/gskvulkanglyphcache.c
gsk/vulkan/gskvulkanglyphcacheprivate.h
gsk/vulkan/gskvulkanrenderer.c
gsk/vulkan/gskvulkanrendererprivate.h
gsk/vulkan/gskvulkanrenderpass.c
gsk/vulkan/gskvulkantextpipeline.c

index a7b0ad39a78164fec37ab9a950587e3ea4d3de97..5ffe62adcc310687dc272e433238700e9ee185b9 100644 (file)
@@ -119,12 +119,17 @@ gsk_vulkan_color_text_pipeline_collect_vertex_data (GskVulkanColorTextPipeline *
 
       if (gi->glyph != PANGO_GLYPH_EMPTY)
         {
-          double cx = (double)(x_position + gi->geometry.x_offset) / PANGO_SCALE;
-          double cy = (double)(gi->geometry.y_offset) / PANGO_SCALE;
+          double cx = (x_position + gi->geometry.x_offset) / PANGO_SCALE;
+          double cy = gi->geometry.y_offset / PANGO_SCALE;
           GskVulkanColorTextInstance *instance = &instances[count];
           GskVulkanCachedGlyph *glyph;
 
-          glyph = gsk_vulkan_renderer_get_cached_glyph (renderer, font, gi->glyph, scale);
+          glyph = gsk_vulkan_renderer_get_cached_glyph (renderer,
+                                                        font,
+                                                        gi->glyph,
+                                                        x_position + gi->geometry.x_offset,
+                                                        gi->geometry.y_offset,
+                                                        scale);
 
           instance->tex_rect[0] = glyph->tx;
           instance->tex_rect[1] = glyph->ty;
index ce3a6947e673db0f5a952219bf4fb0ddaeca306b..830b4d70c9e0efab26e0a72bd9ab48c0bd99920f 100644 (file)
@@ -115,6 +115,8 @@ gsk_vulkan_glyph_cache_class_init (GskVulkanGlyphCacheClass *klass)
 typedef struct {
   PangoFont *font;
   PangoGlyph glyph;
+  guint xshift;
+  guint yshift;
   guint scale; /* times 1024 */
 } GlyphCacheKey;
 
@@ -126,6 +128,8 @@ glyph_cache_equal (gconstpointer v1, gconstpointer v2)
 
   return key1->font == key2->font &&
          key1->glyph == key2->glyph &&
+         key1->xshift == key2->xshift &&
+         key1->yshift == key2->yshift &&
          key1->scale == key2->scale;
 }
 
@@ -134,7 +138,7 @@ glyph_cache_hash (gconstpointer v)
 {
   const GlyphCacheKey *key = v;
 
-  return GPOINTER_TO_UINT (key->font) ^ key->glyph ^ key->scale;
+  return GPOINTER_TO_UINT (key->font) ^ key->glyph ^ (key->xshift << 24) ^ (key->yshift << 26) ^ key->scale;
 }
 
 static void
@@ -267,10 +271,10 @@ render_glyph (Atlas          *atlas,
   gi.glyph = key->glyph;
   gi.geometry.width = value->draw_width * 1024;
   if (key->glyph & PANGO_GLYPH_UNKNOWN_FLAG)
-    gi.geometry.x_offset = 0;
+    gi.geometry.x_offset = key->xshift * 256;
   else
-    gi.geometry.x_offset = - value->draw_x * 1024;
-  gi.geometry.y_offset = - value->draw_y * 1024;
+    gi.geometry.x_offset = key->xshift * 256 - value->draw_x * 1024;
+  gi.geometry.y_offset = key->yshift * 256 - value->draw_y * 1024;
 
   glyphs.num_glyphs = 1;
   glyphs.glyphs = &gi;
@@ -328,18 +332,29 @@ gsk_vulkan_glyph_cache_new (GskRenderer      *renderer,
   return cache;
 }
 
+#define PHASE(x) ((x % PANGO_SCALE) * 4 / PANGO_SCALE)
+
 GskVulkanCachedGlyph *
 gsk_vulkan_glyph_cache_lookup (GskVulkanGlyphCache *cache,
                                gboolean             create,
                                PangoFont           *font,
                                PangoGlyph           glyph,
+                               int                  x,
+                               int                  y,
                                float                scale)
 {
   GlyphCacheKey lookup_key;
   GskVulkanCachedGlyph *value;
+  guint xshift;
+  guint yshift;
+
+  xshift = PHASE (x);
+  yshift = PHASE (y);
 
   lookup_key.font = font;
   lookup_key.glyph = glyph;
+  lookup_key.xshift = xshift;
+  lookup_key.yshift = yshift;
   lookup_key.scale = (guint)(scale * 1024);
 
   value = g_hash_table_lookup (cache->hash_table, &lookup_key);
@@ -374,6 +389,8 @@ gsk_vulkan_glyph_cache_lookup (GskVulkanGlyphCache *cache,
 
       key->font = g_object_ref (font);
       key->glyph = glyph;
+      key->xshift = xshift;
+      key->yshift = yshift;
       key->scale = (guint)(scale * 1024);
 
       if (ink_rect.width > 0 && ink_rect.height > 0)
index b566e5b9bcc09ed6cffdde4c4f0969fcea884324..b31711fe6d0327dbaedbc9b8fcef5c14c6faef5f 100644 (file)
@@ -22,6 +22,9 @@ GskVulkanCachedGlyph *gsk_vulkan_glyph_cache_lookup         (GskVulkanGlyphCache
                                                              gboolean             create,
                                                              PangoFont           *font,
                                                              PangoGlyph           glyph,
+                                                             int                  x,
+                                                             int                  y,
+
                                                              float                scale);
 
 void                  gsk_vulkan_glyph_cache_begin_frame    (GskVulkanGlyphCache *cache);
index 6fc59758c6aa66558340c743d548de4e16fdca67..867f51b5d64a6019a9bdcd9a61245e3c18db4875 100644 (file)
@@ -362,15 +362,6 @@ gsk_vulkan_renderer_ref_texture_image (GskVulkanRenderer *self,
   return image;
 }
 
-guint
-gsk_vulkan_renderer_cache_glyph (GskVulkanRenderer *self,
-                                 PangoFont         *font,
-                                 PangoGlyph         glyph,
-                                 float              scale)
-{
-  return gsk_vulkan_glyph_cache_lookup (self->glyph_cache, TRUE, font, glyph, scale)->texture_index;
-}
-
 GskVulkanImage *
 gsk_vulkan_renderer_ref_glyph_image (GskVulkanRenderer  *self,
                                      GskVulkanUploader  *uploader,
@@ -379,13 +370,26 @@ gsk_vulkan_renderer_ref_glyph_image (GskVulkanRenderer  *self,
   return g_object_ref (gsk_vulkan_glyph_cache_get_glyph_image (self->glyph_cache, uploader, index));
 }
 
+guint
+gsk_vulkan_renderer_cache_glyph (GskVulkanRenderer *self,
+                                 PangoFont         *font,
+                                 PangoGlyph         glyph,
+                                 int                x,
+                                 int                y,
+                                 float              scale)
+{
+  return gsk_vulkan_glyph_cache_lookup (self->glyph_cache, TRUE, font, glyph, x, y, scale)->texture_index;
+}
+
 GskVulkanCachedGlyph *
 gsk_vulkan_renderer_get_cached_glyph (GskVulkanRenderer *self,
                                       PangoFont         *font,
                                       PangoGlyph         glyph,
+                                      int                x,
+                                      int                y,
                                       float              scale)
 {
-  return gsk_vulkan_glyph_cache_lookup (self->glyph_cache, FALSE, font, glyph, scale);
+  return gsk_vulkan_glyph_cache_lookup (self->glyph_cache, FALSE, font, glyph, x, y, scale);
 }
 
 /**
index d492a85b1f16eb46dd7c74e49fa9bce7d5d8c254..eca34ccabd40600ec98fb5709230fcda7773442e 100644 (file)
@@ -30,6 +30,8 @@ typedef struct
 guint                  gsk_vulkan_renderer_cache_glyph      (GskVulkanRenderer *renderer,
                                                              PangoFont         *font,
                                                              PangoGlyph         glyph,
+                                                             int                x,
+                                                             int                y,
                                                              float              scale);
 
 GskVulkanImage *       gsk_vulkan_renderer_ref_glyph_image  (GskVulkanRenderer *self,
@@ -39,6 +41,8 @@ GskVulkanImage *       gsk_vulkan_renderer_ref_glyph_image  (GskVulkanRenderer *
 GskVulkanCachedGlyph * gsk_vulkan_renderer_get_cached_glyph (GskVulkanRenderer *self,
                                                              PangoFont         *font,
                                                              PangoGlyph         glyph,
+                                                             int                x,
+                                                             int                y,
                                                              float              scale);
 
 
index 55f96456a80e39c8d9f294df2895821f59113e74..00fd658d8bfd813669aad36567d2cfee3655fa2c 100644 (file)
@@ -370,6 +370,7 @@ gsk_vulkan_render_pass_add_node (GskVulkanRenderPass           *self,
         int i;
         guint count;
         guint texture_index;
+        gint x_position;
         GskVulkanRenderer *renderer = GSK_VULKAN_RENDERER (gsk_vulkan_render_get_renderer (render));
 
         if (font_has_color_glyphs (font))
@@ -402,11 +403,17 @@ gsk_vulkan_render_pass_add_node (GskVulkanRenderPass           *self,
         op.text.texture_index = G_MAXUINT;
         op.text.scale = self->scale_factor;
 
+        x_position = 0;
         for (i = 0, count = 0; i < num_glyphs; i++)
           {
             const PangoGlyphInfo *gi = &glyphs[i];
 
-            texture_index = gsk_vulkan_renderer_cache_glyph (renderer, (PangoFont *)font, gi->glyph, op.text.scale);
+            texture_index = gsk_vulkan_renderer_cache_glyph (renderer,
+                                                             (PangoFont *)font,
+                                                             gi->glyph,
+                                                             x_position + gi->geometry.x_offset,
+                                                             gi->geometry.y_offset,
+                                                             op.text.scale);
             if (op.text.texture_index == G_MAXUINT)
               op.text.texture_index = texture_index;
             if (texture_index != op.text.texture_index)
@@ -421,6 +428,8 @@ gsk_vulkan_render_pass_add_node (GskVulkanRenderPass           *self,
               }
             else
               count++;
+
+            x_position += gi->geometry.width;
           }
 
         if (op.text.texture_index != G_MAXUINT && count != 0)
index 7cd85c5d9a52ff58547e8705f0c4fa6863da6590..9544c6a7c766fd20ce37450a91c30e04b412aa6a 100644 (file)
@@ -127,12 +127,17 @@ gsk_vulkan_text_pipeline_collect_vertex_data (GskVulkanTextPipeline  *pipeline,
 
       if (gi->glyph != PANGO_GLYPH_EMPTY)
         {
-          double cx = (double)(x_position + gi->geometry.x_offset) / PANGO_SCALE;
-          double cy = (double)(gi->geometry.y_offset) / PANGO_SCALE;
+          double cx = (x_position + gi->geometry.x_offset) / PANGO_SCALE;
+          double cy = gi->geometry.y_offset / PANGO_SCALE;
           GskVulkanTextInstance *instance = &instances[count];
           GskVulkanCachedGlyph *glyph;
 
-          glyph = gsk_vulkan_renderer_get_cached_glyph (renderer, font, gi->glyph, scale);
+          glyph = gsk_vulkan_renderer_get_cached_glyph (renderer,
+                                                        font,
+                                                        gi->glyph,
+                                                        x_position + gi->geometry.x_offset,
+                                                        gi->geometry.y_offset,
+                                                        scale);
 
           instance->tex_rect[0] = glyph->tx;
           instance->tex_rect[1] = glyph->ty;